<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。
//  JCAT 由中国团队开发维护，是一个国际性的项目。
//  正在使用的这个版本是：0.3.1 / SVN信息：$Id: class.JCAT_View.php 1119 2008-10-25 03:55:26Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [HTTP下载] http://jcat.JeCat.cn/download
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.cn/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.cn/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/



JCAT_Package::ImportInterface('JCAT_IView',JCAT::PACKAGE_MVC) ;



/**
 * What's this Class ?
 *
 * @author		alee
 * @access		public
 */
abstract class JCAT_View extends JCAT_EventProcessor implements JCAT_IView
{


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sName		string					视图名称
	 * @param	$aParent	JCAT_IViewContainer		父视图 或 控制器
	 * @return	void
	 */
	public function JCAT_View( $sName, JCAT_IViewContainer $aParent=null ) 
	{
		JCAT_ASSERT::ASSERT_STRING($sName) ;
		
		$this->sName = $sName ;
		$this->aParent = $aParent ;
		
		$this->aViewContainer = new _JCAT_MVCObjectContainer('JCAT_IView') ;
		$this->aUICtrlContainer = new _JCAT_MVCObjectContainer('JCAT_IUICtrl') ;
		
		// 数据交换器
		$this->aDataExchanger = new JCAT_MVCDataExchanger($this) ;
		
		// 注册一个全局名称
		self::RegisterGlobalName($this) ;
	}


	/**
	 * 
	 *
	 * @access	public
	 * @return	JCAT_UI
	 */
	public function GetUI()
	{ return $this->aUI ; }

	/**
	 * 
	 *
	 * @access	public
	 * @param	$aUI	JCAT_UI		UI对象
	 * @return	old_value
	 */
	public function SetUI( JCAT_UI $aUI )
	{
		$old_value = $this->aUI ;
		$this->aUI = $aUI ;
		return $old_value ;
	}
	

	/**
	 * what's this
	 * 
	 * @access	public
	 * @return	JCAT_MVCDataExchanger
	 */
	public function GetDataExchanger()
	{
		return $this->aDataExchanger ;
	}
			
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param 	$aDataExchanger	 JCAT_MVCDataExchanger
	 * @return	old_value
	 */
	public function SetDataExchanger(JCAT_MVCDataExchanger $aDataExchanger)
	{
		$old_value = $this->aDataExchanger ;
		$this->aDataExchanger = $aDataExchanger ;
		return $old_value ;
	}
	


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$aView		JCAT_IView		What's this Parameter ?
	 * @param	$sName=''	string			What's this Parameter ?
	 * @static
	 * @return	old_value
	 */
	static public function RegisterGlobalName( JCAT_IView $aView, $sName='' ) 
	{
		JCAT_ASSERT::ASSERT_STRING($sName) ;
		if( $sName==='' )
			$sName = $aView->GetName() ;
			
		$old_value = isset(self::$arrGlobalViews[$sName])? self::$arrGlobalViews[$sName]: null ;
		self::$arrGlobalViews[$sName] = $aView ;
		return $old_value ;
	}

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$ViewOrName		JCAT_IView,string		What's this Parameter ?
	 * @static
	 * @return	void
	 */
	static public function UnregisterGlobalName( $ViewOrName ) 
	{
		JCAT_ASSERT::ASSERT_ISTHESE($ViewOrName,array('JCAT_IView','string')) ;
		
		// 传入 视图名称
		if( is_string($ViewOrName) )
		{
			// $sKey =& $ViewOrName ;
			if( !isset(self::$arrGlobalViews[$ViewOrName]) )
				return null ;

			unset(self::$arrGlobalViews[$ViewOrName]) ;
		}
		
		// 传入 视图对象
		else
		{
			// 删除 该对象 的所有 引用
			while( 1 )
			{
				$sName = array_search($ViewOrName,self::$arrGlobalViews) ;
			
				if( in_array($sName,array(null,false),true) )
				{
					break ;
				}
				
				self::UnregisterGlobalName( strval($sName) ) ;
			}
		}
		
	}
	


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sName	string	What's this Parameter ?
	 * @static
	 * @return	JCAT_IView
	 */
	static public function GetViewByGlobalName( $sName ) 
	{
		JCAT_ASSERT::ASSERT_STRING($sName) ;
		return isset(self::$arrGlobalViews[$sName])? self::$arrGlobalViews[$sName]: null ;
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sInstanceNameOrPath	string	What's this Parameter ?
	 * @static
	 * @return	JCAT_IView
	 */
	public function ImportUICtrlInstance($sInstanceNameOrPath)
	{
		JCAT_ASSERT::ASSERT_STRING($sInstanceNameOrPath) ;
		$aUICtrl = JCAT_Package::ImportInstance($sInstanceNameOrPath) ;
		
		JCAT_ASSERT::ASSERT_INSTANCE($aUICtrl,'JCAT_IUICtrl',JCAT_Language::SentenceEx('参数 $sInstanceNameOrPath 必须为一个JCAT_IUICtrl 实例','JCAT',null)) ;
		$this->AddUICtrl($aUICtrl) ;
	}

	//// 实现 JCAT_IView 接口 ///////////////////////////////////////////////////////////////////////////////
	
	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	string
	 */
	public function GetName(  )
	{ return $this->sName ; }



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sName	string	What's this Parameter ?
	 * @return	old_var
	 */
	public function SetName( $sName )
	{
		JCAT_ASSERT::ASSERT_STRING($sName) ;
		
		$old_var = $this->sName ;
		$this->sName = $sName ;
		return $old_var ;
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	JCAT_IViewContainer
	 */
	public function GetParent(  ) 
	{
		if($this->aParent===null)
		{
			return null ;
		}
		else 
		{
			JCAT_ASSERT::ASSERT_INSTANCE($this->aParent,'JCAT_IViewContainer') ;
			return $this->aParent ;
		}
	}

	/**
	 * 返回是否顶层视图
	 *
	 * @access	public
	 * @return	bool
	 */
	public function IsTopView()
	{
		return !JCAT_Global::IsKindOf($this->GetParent(),'JCAT_IView') ;
	}

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	JCAT_IController
	 */
	public function GetParentController()
	{
		$aParent = $this->GetParent() ;
		
		if( JCAT_Global::IsKindOf($aParent,'JCAT_IController') )
			return $aParent ;

		if( JCAT_Global::IsKindOf($aParent,'JCAT_IView') )
			return $aParent->GetParentController() ;

		else
			return null ;
		
		JCAT_ASSERT::ASSERT_(0,'!?') ;
		
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$aDocument	JCAT_IDocument	What's this Parameter ?
	 * @return	old_var
	 */
	public function SetDocument( JCAT_IDocument $aDocument )
	{
		if( $this->aDocument )
		{
			// 从旧文档中移除
			$this->aDocument->RemoveView( $this ) ;
			
			// 保存 旧文档
			$old_var = $this->aDocument ;
		}
		else
		{
			$old_var = null ;
		}
		
		// 设置新文档
		$this->aDocument = $aDocument ;
		$aDocument->AddView($this,$this->GetName()) ;

		// 子视图文档同置
		if( $this->GetSynDocumentForChildren() )
		{
			// 迭代 子视图
			$aViewIterator = $this->CreateViewIterator() ;
			$aViewIterator->First() ;
			while( !$aViewIterator->IsDone() )
			{
				$aView = $aViewIterator->Current() ;
				
				$aView->SetDocument($aDocument) ;
				
				$aViewIterator->Next() ;
			}
		}
		
		return $old_var ;
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	JCAT_IDocument, null
	 */
	public function GetDocument()
	{ return $this->aDocument ; }

	
	/**
	 * 彻底 销毁一个视图 在  MVC 系统中的所有引用，以便在不需要该视图时能够立刻回收：
	 *  文档 对该视图的引用
	 *  控制器 对该视图的引用
	 *  视图的全局名称上的引用
	 *  ... ...
	 * 
	 * @access	public
	 * @return	void
	 */
	public function Destroy()
	{
		// 清除子视图
		$this->aViewContainer->DestroyAll() ;
		
		// 解除文档中的引用
		if( $this->aDocument )
		{
			$this->aDocument->RemoveView( $this ) ;
		}
		
		// 解除 父容器对象 的引用
		$aViewParent = $this->GetParent() ;
		if( $aViewParent )
		{
			JCAT_ASSERT::ASSERT_INSTANCE($aViewParent,'JCAT_IViewContainer') ;
			$aViewParent->RemoveView($this) ;
		}

		// 清除 视图的全局名称
		self::UnregisterGlobalName($this) ;
		
		// 释放 对 其他对象的 引用
		$this->SetDocument(null) ;
		$this->aParent = null ;
		unset($this->aDataExchanger) ;
	}
	
	/**
	 * 子视图  数据交换
	 *
	 * @access	protected
	 * @param	$nExchangeWay=self::UICTRL_TO_DOC	int	交换方向
	 * @return	void
	 */
	protected function ExchangeDataForChildView( $nExchangeWay=JCAT_IViewForm::UICTRL_TO_DOC )
	{
		// 迭代 子视图
		$aViewIterator = $this->CreateViewIterator() ;
		$aViewIterator->First() ;
		while( !$aViewIterator->IsDone() )
		{
			$aView = $aViewIterator->Current() ;
			$aView->ExchangeData($nExchangeWay) ;
			
			$aViewIterator->Next() ;
		}
	}
	
	
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$nExchangeWay=self::UICTRL_TO_DOC	int		交换方向
	 * @param	$sTheUICtrlName=null				string	指定的UI控件
	 * @param 	$bForChildren						bool
	 * @return	void
	 */
	public function ExchangeData( $nExchangeWay=JCAT_IViewForm::UICTRL_TO_DOC, $sTheUICtrlName=null, $bForChildren=true )
	{
		JCAT_ASSERT::ASSERT_ISTHESE($sTheUICtrlName,array('string','null'));
		
		$aDataExchanger = $this->GetDataExchanger() ;
		
		// 交换所有的
		if($sTheUICtrlName===null)
		{
			$aDataExchanger->ExchangeData($nExchangeWay) ;
			
			// 子视图 数据交换
			if($bForChildren)
			{
				$this->ExchangeDataForChildView($nExchangeWay) ;
			}
		}
		
		// 交换指定 UICtrl
		else
		{
			$aDataExchanger->ExchangeOneData($sTheUICtrlName,$nExchangeWay) ;
		}
	}

	
	/**
	 * 直接取得一个 UI控件 的 交换值
	 * 
	 * @access	public
	 * @param	$sUICtrlName	string		
	 * @return	mixed
	 */
	public function GetUICtrlExchangeData($sUICtrlName)
	{
		JCAT_ASSERT::ASSERT_STRING($sUICtrlName) ;
		$aUICtrl = $this->GetUICtrl($sUICtrlName) ;
		JCAT_ASSERT::ASSERT_INSTANCE($aUICtrl,'JCAT_IUICtrl',JCAT_Language::SentenceEx('视图 %s 中，没有找到名为“%s”的UI控件。','JCAT',null,$this->GetName(),$sUICtrlName)) ;
		JCAT_ASSERT::ASSERT_INSTANCE($aUICtrl,'JCAT_IUICtrlForm',JCAT_Language::SentenceEx('UI控件%s尚未实现 JCAT_IUICtrlForm 接口，无法取得交换值。','JCAT',null,$this->GetName(),$sUICtrlName)) ;

		return $aUICtrl->GetExchangeData() ;		
	}

	/**
	 * 直接设置一个 UI控件 的 交换值
	 * 
	 * @access	public
	 * @param	$sUICtrlName	string	
	 * @param	$Value			mixed		
	 * @return	mixed
	 */
	public function SetUICtrlExchangeData($sUICtrlName,$Value)
	{
		JCAT_ASSERT::ASSERT_STRING($sUICtrlName) ;
		$aUICtrl = $this->GetUICtrl($sUICtrlName) ;
		JCAT_ASSERT::ASSERT_INSTANCE($aUICtrl,'JCAT_IUICtrl',JCAT_Language::SentenceEx('视图 %s 中，没有找到名为“%s”的UI控件。','JCAT',null,$this->GetName(),$sUICtrlName)) ;
		JCAT_ASSERT::ASSERT_INSTANCE($aUICtrl,'JCAT_IUICtrlForm',JCAT_Language::SentenceEx('UI控件%s尚未实现 JCAT_IUICtrlForm 接口，无法取得交换值。','JCAT',null,$this->GetName(),$sUICtrlName)) ;
		
		$aUICtrl->SetDataByExchange(&$Value) ;
	}
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param 	$bForChildren	bool
	 * @return	void
	 */
	public function Update($bForChildren=true)
	{
		// 通知事件
		$this->OnUpdate($bForChildren) ;
		
		// 更新输入栏位
		if( JCAT_Global::HasImplementedTo($this,'JCAT_IViewForm') )
		{
			$this->ExchangeData( JCAT_IViewForm::DOC_TO_UICTRL, null, $bForChildren ) ;
		}
	}
	
	/**
	 * 当 Update 被调用时， 此事件被触发
	 * 
	 * @access	public
	 * @param 	$bForChildren	bool
	 * @return	void
	 */
	public function OnUpdate($bForChildren=true)
	{
		// 在派生类中实现
	}

	/**
	 * 校验 UICtrl 中的用户输入内容
	 *
	 * @access	public
	 * @param	$bVerifyAll=true		bool	是否校验所有 UICtrl；  如果为False，在遇到第一个输入不正确的 UICtrl 时返回。
	 * @return	bool
	 */
	public function VerifyData( $bVerifyAll=true )
	{
		$bRet = true ;
		
		// 对 本视图 的 控件进行检查
		$aIterator = $this->CreateUICtrlIterator() ;
		$aIterator->First() ;
		while( !$aIterator->IsDone() )
		{
			$aUICtrl = $aIterator->Current() ;
			
			if( JCAT_Global::HasImplementedTo($aUICtrl,'JCAT_IUICtrlForm') and !$aUICtrl->VerifyData() )
			{
				if( !$bVerifyAll )
					return false ;
				else
					$bRet = false ;
			}
			
			$aIterator->Next() ;
		}
		
		// 对 检查 子视图
		if( !$this->VerifyDataForChildView($bVerifyAll) )
			$bRet = false ;
		
		return $bRet ;
	}
	
	
	
	
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$bVerifyAll=true		bool	是否校验所有 UICtrl；  如果为False，在遇到第一个输入不正确的 UICtrl 时返回。
	 * @return	bool
	 */
	protected function VerifyDataForChildView( $bVerifyAll=true )
	{
		$bRet = true ;
		
		// 迭代 子视图
		$aViewIterator = $this->CreateViewIterator() ;
		$aViewIterator->First() ;
		while( !$aViewIterator->IsDone() )
		{
			$aView = $aViewIterator->Current() ;
			
			// 仅 Form 子视图
			if( JCAT_Global::HasImplementedTo($aView,'JCAT_IViewForm') )
			{
				// 遇到 失败的 子视图
				if( !$aView->VerifyData($bVerifyAll) )
				{
					if(!$bVerifyAll)
						return false ;
					else
						$bRet = false ;
				}
			}
			
			$aViewIterator->Next() ;
		}
		
		return $bRet ;
	}
	
	
	
	

	///////// 实现 JCAT_IViewContainer 接口 ///////////////////////////////////////////////////////////////////////////////

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$aView		JCAT_IView		What's this Parameter ?
	 * @param	$sName=null	string			What's this Parameter ?
	 * @return	void
	 */
	public function AddView( JCAT_IView $aView, $sName=null )
	{ return $this->aViewContainer->Add($aView,$sName) ; }
	

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sViewName	JCAT_IView		What's this Parameter ?
	 * @return	void
	 */
	public function RemoveView( JCAT_IView $aView )
	{ return $this->aViewContainer->Remve($aView) ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sName	string	What's this Parameter ?
	 * @return	
	 */
	public function GetView( $sName )
	{ return $this->aViewContainer->Get($sName) ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	int
	 */
	public function GetViewCount(  ) 
	{ return $this->aViewContainer->GetObjectCount() ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	int
	 */
	public function ClearView(  )
	{ return $this->aViewContainer->ClearObject() ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	JCAT_ArrayIterator
	 */
	public function CreateViewIterator(  )
	{ return $this->aViewContainer->CreateObjectIterator() ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	array
	 */
	public function CreateViewMemento(  )
	{ return $this->aViewContainer->CreateObjectMemento() ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$arrMemento	array	What's this Parameter ?
	 * @return	void
	 */
	public function SetViewMemento( $arrMemento )
	{ return $this->aViewContainer->SetObjectMemento($arrMemento) ; }



	
	
	


	///////// 实现 JCAT_IUICtrlContainer 接口 ///////////////////////////////////////////////////////////////////////////////
	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$aUICtrl							What's this Parameter ?
	 * @param	$sExchangeDocumentDataName=null		数据交换的 文档数据名称
	 * @return	void
	 */
	public function AddUICtrl( JCAT_IUICtrl $aUICtrl, $sExchangeDocumentDataName=null )
	{
		$aUICtrl->SetParentView($this) ;
		$this->aUICtrlContainer->Add($aUICtrl) ;
		
		if($sExchangeDocumentDataName!==null)
		{
			$aDataExchanger = $this->GetDataExchanger() ;
			$aDataExchanger->LinkUICtrlToDocumentData($aUICtrl->GetName(),$sExchangeDocumentDataName) ;
		}
	}

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sName	string	What's this Parameter ?
	 * @return	JCAT_IUICtrl
	 */
	public function GetUICtrl( $sName )
	{ return $this->aUICtrlContainer->Get($sName) ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	int
	 */
	public function GetUICtrlCount(  ) 
	{ return $this->aUICtrlContainer->GetObjectCount() ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	int
	 */
	public function ClearUICtrl(  )
	{ return $this->aUICtrlContainer->ClearObject() ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	JCAT_ArrayIterator
	 */
	public function CreateUICtrlIterator(  )
	{ return $this->aUICtrlContainer->CreateObjectIterator() ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	array
	 */
	public function CreateUICtrlMemento(  )
	{ return $this->aUICtrlContainer->CreateObjectMemento() ; }

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$arrMemento	array	What's this Parameter ?
	 * @return	void
	 */
	public function SetUICtrlMemento( array $arrMemento )
	{ return $this->aUICtrlContainer->SetObjectMemento($arrMemento) ; }
	

	/**
	 * 设置:子视图文档同置
	 *
	 * @access	public
	 * @param	$bAutoSynDocumentForChildren=true		bool	子视图文档同步
	 * @return	old_value
	 */
	public function SetSynDocumentForChildren($bAutoSynDocumentForChildren=true)
	{
		$old_value = $this->bAutoSynDocumentForChildren ;
		$this->bAutoSynDocumentForChildren = $bAutoSynDocumentForChildren? true: false ;
		return $old_value ;
	}
	
	/**
	 * 取得:子视图文档同置
	 *
	 * @access	public
	 * @return	bool
	 */
	public function GetSynDocumentForChildren()
	{
		return $this->bAutoSynDocumentForChildren ;
	}


	// 属性 ///////////////////////////////////////////////////////////////////////////////

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		JCAT_IDocument
	 */
	private $aDocument ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		_JCAT_MVCObjectContainer
	 */
	private $aUICtrlContainer ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		_JCAT_MVCObjectContainer
	 */
	private $aViewContainer ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		JCAT_IViewContainer
	 */
	private $aParent ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sName ;


	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		array
	 * @static
	 */
	static private $arrGlobalViews ;
	
	
	private $aUI ;
	
	private $aDataExchanger ;

	
	/**
	 * 对象属性 子视图文档同步
	 * 
	 * @access	private
	 * @var		bool
	 */
	private $bAutoSynDocumentForChildren = false ;
	
}


?>